use crate::local_time::{self, CalType};
use core::panic;
use csv::Reader;
// use serde::Deserialize;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::error::Error;
use std::path::Path;

static TIME_M_START: usize = 93000000;

/// tick数据
#[derive(Debug, Deserialize, Clone)]
pub struct Tick {
    #[serde(rename = "nTime")]
    time: usize, // 时间
    #[serde(rename = "Status")]
    status: String, // 交易状态，取79
    #[serde(rename = "PreClose")]
    pre_close: usize, // 昨收
    #[serde(rename = "nPrice")]
    price: usize, // 最新价
    #[serde(rename = "nAskPrice1")]
    n_ask_pce1: usize, // 卖1价
    #[serde(rename = "nAskPrice2")]
    n_ask_pce2: usize, // 卖2价
    #[serde(rename = "nAskPrice3")]
    n_ask_pce3: usize, // 卖3价
    #[serde(rename = "nAskPrice4")]
    n_ask_pce4: usize, // 卖4价
    #[serde(rename = "nAskPrice5")]
    n_ask_pce5: usize, // 卖5价
    #[serde(rename = "nAskPrice6")]
    n_ask_pce6: usize, // 卖6价
    #[serde(rename = "nAskPrice7")]
    n_ask_pce7: usize, // 卖7价
    #[serde(rename = "nAskPrice8")]
    n_ask_pce8: usize, // 卖8价
    #[serde(rename = "nAskPrice9")]
    n_ask_pce9: usize, // 卖9价
    #[serde(rename = "nAskPrice10")]
    n_ask_pce10: usize, // 卖10价
    #[serde(rename = "nAskVolume1")]
    n_ask_vume1: usize, // 卖1量
    #[serde(rename = "nAskVolume2")]
    n_ask_vume2: usize, // 卖2量
    #[serde(rename = "nAskVolume3")]
    n_ask_vume3: usize, // 卖3量
    #[serde(rename = "nAskVolume4")]
    n_ask_vume4: usize, // 卖4量
    #[serde(rename = "nAskVolume5")]
    n_ask_vume5: usize, // 卖5量
    #[serde(rename = "nAskVolume6")]
    n_ask_vume6: usize, // 卖6量
    #[serde(rename = "nAskVolume7")]
    n_ask_vume7: usize, // 卖7量
    #[serde(rename = "nAskVolume8")]
    n_ask_vume8: usize, // 卖8量
    #[serde(rename = "nAskVolume9")]
    n_ask_vume9: usize, // 卖9量
    #[serde(rename = "nAskVolume10")]
    n_ask_vume10: usize, // 卖10量
    #[serde(rename = "nBidPrice1")]
    n_bid_pce1: usize, // 买1价
    #[serde(rename = "nBidPrice2")]
    n_bid_pce2: usize, // 买2价
    #[serde(rename = "nBidPrice3")]
    n_bid_pce3: usize, // 买3价
    #[serde(rename = "nBidPrice4")]
    n_bid_pce4: usize, // 买4价
    #[serde(rename = "nBidPrice5")]
    n_bid_pce5: usize, // 买5价
    #[serde(rename = "nBidPrice6")]
    n_bid_pce6: usize, // 买6价
    #[serde(rename = "nBidPrice7")]
    n_bid_pce7: usize, // 买7价
    #[serde(rename = "nBidPrice8")]
    n_bid_pce8: usize, // 买8价
    #[serde(rename = "nBidPrice9")]
    n_bid_pce9: usize, // 买9价
    #[serde(rename = "nBidPrice10")]
    n_bid_pce10: usize, // 买10价
    #[serde(rename = "nBidVolume1")]
    n_bid_vume1: usize, // 买1量
    #[serde(rename = "nBidVolume2")]
    n_bid_vume2: usize, // 买2量
    #[serde(rename = "nBidVolume3")]
    n_bid_vume3: usize, // 买3量
    #[serde(rename = "nBidVolume4")]
    n_bid_vume4: usize, // 买4量
    #[serde(rename = "nBidVolume5")]
    n_bid_vume5: usize, // 买5量
    #[serde(rename = "nBidVolume6")]
    n_bid_vume6: usize, // 买6量
    #[serde(rename = "nBidVolume7")]
    n_bid_vume7: usize, // 买7量
    #[serde(rename = "nBidVolume8")]
    n_bid_vume8: usize, // 买8量
    #[serde(rename = "nBidVolume9")]
    n_bid_vume9: usize, // 买9量
    #[serde(rename = "nBidVolume10")]
    n_bid_vume10: usize, // 买10量
    #[serde(rename = "HighLimited")]
    high_limited: usize, // 涨停价
    #[serde(rename = "LowLimited")]
    low_limited: usize, // 跌停价
}

impl Tick {
    // 返回十档买价和买量的信息
    pub fn bid_info_10(&self) -> Info10 {
        let mut bid_info = Info10::new();

        bid_info.time = self.time;

        bid_info.info_1_vec.push(Info1 {
            price: self.n_bid_pce1,
            volume: self.n_bid_vume1,
        });
        bid_info.info_1_vec.push(Info1 {
            price: self.n_bid_pce2,
            volume: self.n_bid_vume2,
        });
        bid_info.info_1_vec.push(Info1 {
            price: self.n_bid_pce3,
            volume: self.n_bid_vume3,
        });
        bid_info.info_1_vec.push(Info1 {
            price: self.n_bid_pce4,
            volume: self.n_bid_vume4,
        });
        bid_info.info_1_vec.push(Info1 {
            price: self.n_bid_pce5,
            volume: self.n_bid_vume5,
        });
        bid_info.info_1_vec.push(Info1 {
            price: self.n_bid_pce6,
            volume: self.n_bid_vume6,
        });
        bid_info.info_1_vec.push(Info1 {
            price: self.n_bid_pce7,
            volume: self.n_bid_vume7,
        });
        bid_info.info_1_vec.push(Info1 {
            price: self.n_bid_pce8,
            volume: self.n_bid_vume8,
        });
        bid_info.info_1_vec.push(Info1 {
            price: self.n_bid_pce9,
            volume: self.n_bid_vume9,
        });
        bid_info.info_1_vec.push(Info1 {
            price: self.n_bid_pce10,
            volume: self.n_bid_vume10,
        });

        bid_info
    }

    // 返回十档卖价和十档卖量
    pub fn ask_info_10(&self) -> Info10 {
        let mut ask_info = Info10::new();

        ask_info.time = self.time;

        ask_info.info_1_vec.push(Info1 {
            price: self.n_ask_pce1,
            volume: self.n_ask_vume1,
        });
        ask_info.info_1_vec.push(Info1 {
            price: self.n_ask_pce2,
            volume: self.n_ask_vume2,
        });
        ask_info.info_1_vec.push(Info1 {
            price: self.n_ask_pce3,
            volume: self.n_ask_vume3,
        });
        ask_info.info_1_vec.push(Info1 {
            price: self.n_ask_pce4,
            volume: self.n_ask_vume4,
        });
        ask_info.info_1_vec.push(Info1 {
            price: self.n_ask_pce5,
            volume: self.n_ask_vume5,
        });
        ask_info.info_1_vec.push(Info1 {
            price: self.n_ask_pce6,
            volume: self.n_ask_vume6,
        });
        ask_info.info_1_vec.push(Info1 {
            price: self.n_ask_pce7,
            volume: self.n_ask_vume7,
        });
        ask_info.info_1_vec.push(Info1 {
            price: self.n_ask_pce8,
            volume: self.n_ask_vume8,
        });
        ask_info.info_1_vec.push(Info1 {
            price: self.n_ask_pce9,
            volume: self.n_ask_vume9,
        });
        ask_info.info_1_vec.push(Info1 {
            price: self.n_ask_pce10,
            volume: self.n_ask_vume10,
        });

        ask_info
    }
}

pub struct TickDatas {
    datas: Vec<Tick>,
}

impl TickDatas {
    // 加载数据
    pub fn new() -> Result<TickDatas, Box<dyn Error>> {
        let tick_path = Path::new("src/resource/601012.SH.Tick.csv");
        let mut tick_rdr = Reader::from_path(tick_path).unwrap();

        let mut tick_vec = Vec::new();

        for result in tick_rdr.deserialize() {
            let record: Tick = result?;
            // 筛选时间
            if record.status == "79" {
                tick_vec.push(record);
            }
        }

        Ok(TickDatas { datas: tick_vec })
    }

    // 获取某个时间点之后第一条报价数据
    pub fn pick_after_time(&self, time_ms: usize) -> Result<Tick, Box<dyn Error>> {
        if self.datas.len() == 0 {
            panic!("未找到符合要求的报价数据");
        }

        for data in &self.datas {
            if data.time >= time_ms {
                return Ok(data.clone());
            }
        }

        panic!("未找到符合要求的报价数据")
    }

    // 获取某一时刻30秒之后的所有买1数据
    pub fn get_bid_1_datas_in_30_seconds(&self, time_ms: usize) -> Vec<Info1> {
        self.get_bid_1_datas_by_ms(time_ms, 30_000_usize)
    }

    // 获取某一时刻ms毫秒之后的所有买1数据
    fn get_bid_1_datas_by_ms(&self, time_ms: usize, ms: usize) -> Vec<Info1> {
        let start = time_ms;
        let end = local_time::cal_time_ms(time_ms, ms, CalType::ADD);

        let mut result = Vec::new();
        for tick in &self.datas {
            if tick.time > end {
                break;
            }

            if tick.time >= start {
                result.push(Info1 {
                    price: tick.n_bid_pce1,
                    volume: tick.n_bid_vume1,
                });
            }
        }

        result
    }
}

/// 买（卖）价和买（卖）量信息
pub struct Info1 {
    pub price: usize,
    pub volume: usize,
}

/// 十档买（卖）价和十档买（卖）量的信息
pub struct Info10 {
    pub time: usize,
    pub info_1_vec: Vec<Info1>,
}

impl Info10 {
    // 每个档位和价格初始化长度为10
    pub fn new() -> Self {
        Info10 {
            time: 93000,
            info_1_vec: Vec::<Info1>::with_capacity(10),
        }
    }
}

/// transaction数据
#[derive(Debug, Deserialize, Clone)]
pub struct Transaction {
    #[serde(rename = "Time")]
    pub time: usize, // 时间
    #[serde(rename = "Price")]
    pub price: usize, // 成交价格
}
impl Ord for Transaction {
    fn cmp(&self, other: &Self) -> Ordering {
        self.price.cmp(&other.price)
    }
}
impl Eq for Transaction {}
impl PartialOrd for Transaction {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.price.partial_cmp(&other.price)
    }
}
impl PartialEq for Transaction {
    fn eq(&self, other: &Self) -> bool {
        self.price == other.price
    }
}

impl Transaction {
    // 计算成交涨价百分比
    pub fn get_percent(&self, min: &Self) -> f32 {
        (self.price as f32 - min.price as f32) / self.price as f32
    }
}

pub struct TransactionDatas {
    pub datas: Vec<Transaction>,
}

impl TransactionDatas {
    pub fn new() -> Result<TransactionDatas, Box<dyn Error>> {
        let tran_path = Path::new("src/resource/601012.SH.Transaction.csv");
        let mut tran_rdr = Reader::from_path(tran_path).unwrap();

        let mut tran_vec = Vec::new();

        for result in tran_rdr.deserialize() {
            let record: Transaction = result?;
            // 筛选合适时间
            if local_time::in_interval(record.time / 1000 as usize) {
                tran_vec.push(record);
            }
        }

        Ok(TransactionDatas { datas: tran_vec })
    }

    pub fn build_tran_mapping(&self) -> (HashMap<usize, usize>, HashMap<usize, usize>) {
        let map_slice_num = 4 * 60 * 60; // 每秒一个slice，计算交易时间所需要的秒数
        let mut start_mapping = HashMap::<usize, usize>::with_capacity(map_slice_num);
        let mut end_mapping = HashMap::<usize, usize>::with_capacity(map_slice_num);

        let mut current = TIME_M_START / 1_000;
        start_mapping.insert(current, 0_usize);

        for (i, tran) in (&self.datas).into_iter().enumerate() {
            if tran.time / 1000 != current {
                end_mapping.insert(current, i - 1);
                current = tran.time / 1000;
                start_mapping.insert(current, i);
            }
        }
        end_mapping.insert(self.datas.last().unwrap().time / 1000, self.datas.len() - 1);

        (start_mapping, end_mapping)
    }
}

#[cfg(test)]
mod tests {
    use super::{TickDatas, TransactionDatas};

    #[test]
    fn test_pick_after_time() {
        let tick_datas = TickDatas::new().unwrap();
        let tick = tick_datas.pick_after_time(132724070).unwrap();

        assert_eq!(tick.time, 132726000);
    }

    #[test]
    pub fn test_get_bid_1_datas_by_second() {
        let start = 101020000_usize;

        let tick_datas = TickDatas::new().unwrap();
        let result = tick_datas.get_bid_1_datas_in_30_seconds(start);

        assert_eq!(result.len(), 11);
    }

    #[test]
    pub fn test_load_tran_datas() {
        let tran_datas = TransactionDatas::new().unwrap();

        assert_eq!(tran_datas.datas.len(), 396322);
    }

    #[test]
    pub fn test_load_tick_datas() {
        let tick_datas = TickDatas::new().unwrap();

        assert_eq!(tick_datas.datas.len(), 4805);
    }
}
